package com.zl.common.aop;
import java.util.List;
import java.util.zip.DataFormatException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.NoHandlerFoundException;

import com.zl.common.dto.ResDTO;
import com.zl.common.enums.resp.GlobalRespEnum;
import com.zl.common.exception.BizException;
import com.zl.common.utils.ReturnUtil;
 
/**
 * 全局异常捕获处理，返回json
 * @param <T>
 */
@ControllerAdvice
public class GlobalExceptionHandler<T> {
    private static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 按http状态
     * 捕捉404异常
     */
    @ResponseBody
    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ExceptionHandler(NoHandlerFoundException.class)
    public ResDTO<T> handle404(NoHandlerFoundException e) {
        LOGGER.error("路径不存在:{}，{}",e.getMessage(),e);
        return ReturnUtil.returnDATA(GlobalRespEnum.NOT_FOUND);
    }
    
    /**
     * http请求的方法不正确
     */
    @ResponseBody
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public ResDTO<T> httpRequestMethodNotSupportedExceptionHandler(HttpRequestMethodNotSupportedException e) {
        LOGGER.error("http请求方法不正确:{}，{}",e.getMessage(),e);
        return ReturnUtil.returnDATA(GlobalRespEnum.RequestMethodNotAllowed);
    }
    /**
     * http请求的方法不正确
     */
    @ResponseBody
    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    public ResDTO<T> httpMediaTypeNotSupportedExceptionHandler(HttpMediaTypeNotSupportedException e) {
        LOGGER.error("http请求方法不正确:{}，{}",e.getMessage(),e);
        return ReturnUtil.returnDATA(GlobalRespEnum.RequestMethodNotAllowed);
    }
    /**
     * 请求参数不全
     */
    @ResponseBody
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public ResDTO<T> missingServletRequestParameterExceptionHandler(MissingServletRequestParameterException e) {
        LOGGER.error("请求参数不全:{}，{}",e.getMessage(),e);
        return ReturnUtil.returnDATA(GlobalRespEnum.MissingServletRequestParameter);
    }
 
    /**
     * 请求参数类型不正确
     */
    @ResponseBody
    @ExceptionHandler(TypeMismatchException.class)
    public ResDTO<T> typeMismatchExceptionHandler(TypeMismatchException e) {
        LOGGER.error("请求参数类型不正确:{}，{}",e.getMessage(),e);
        return ReturnUtil.returnDATA(GlobalRespEnum.TypeMismatchException);
    }
 
    /**
     * 数据格式不正确
     */
    @ResponseBody
    @ExceptionHandler(DataFormatException.class)
    public ResDTO<T> dataFormatExceptionHandler(DataFormatException e) {
        LOGGER.error("数据格式不正确:{}，{}",e.getMessage(),e);
        return ReturnUtil.returnDATA(GlobalRespEnum.DataFormatException);
    }
 
    /**
     * 非法输入
     */
    @ResponseBody
    @ExceptionHandler(IllegalArgumentException.class)
    public ResDTO<T> illegalArgumentExceptionHandler(IllegalArgumentException e) {
        LOGGER.error("非法输入:{}，{}",e.getMessage(),e);
        return ReturnUtil.returnDATA(GlobalRespEnum.IllegalArgumentException);
    }
    
    @ResponseBody
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public ResDTO<T> notReadableExceptionHandler(HttpMessageNotReadableException e) {
        LOGGER.error("body异常:{}，{}",e.getMessage(),e);
        return ReturnUtil.returnDATA(GlobalRespEnum.HttpMessageNotReadableException);
    }
 
    @ResponseBody
    @ExceptionHandler({BindException.class,MethodArgumentNotValidException.class})
    public ResDTO<T> validExceptionHandler(Exception e) {
        LOGGER.error("参数校验异常:{}，{}",e.getMessage(),e);
        List<FieldError> errors = null;
        if (e instanceof BindException) {
            errors = ((BindException) e).getBindingResult().getFieldErrors();
           
        } else if (e instanceof MethodArgumentNotValidException) {
            errors = ((MethodArgumentNotValidException) e).getBindingResult().getFieldErrors();
        }
        StringBuilder msg = new StringBuilder();
        if (errors != null && errors.size()>0) {
            //去掉一级名字
            for(FieldError x: errors){
                 msg.append("["+x.getField()+">>" + x.getDefaultMessage()+"]");
            }
        }
        return ReturnUtil.returnDATA(GlobalRespEnum.INVALID_PARAMETER.getCode()
                ,GlobalRespEnum.INVALID_PARAMETER.getMsg()+ (msg.length()>0?"："+msg.toString():""));
    }
    
    @ResponseBody
    @ExceptionHandler(BizException.class)
    public ResDTO<T> bizExceptionHandler(BizException e) {
        LOGGER.error("业务异常:{}，{}",e.getMessage(),e);
        return ReturnUtil.returnDATA(e.getErrorCode(),e.getErrorMessage());
    }
    
    @ExceptionHandler  //处理其他异常
    @ResponseBody
    public ResDTO<T> allExceptionHandler(Exception e){
        LOGGER.error("Exception异常:{}", e);
        return ReturnUtil.errorDATA(null);
    }
}